package com.cskaoyan.wordmemorize.common.aspect;

import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.common.aspect.operate.OperateLog;
import com.cskaoyan.wordmemorize.common.aspect.operate.OperateLogConstant;
import com.cskaoyan.wordmemorize.dao.entity.OperateLogDO;
import com.cskaoyan.wordmemorize.dao.mapper.OperateLogMapper;
import com.cskaoyan.wordmemorize.dto.admin.DeleteLevelOperateDTO;
import com.cskaoyan.wordmemorize.dto.admin.DeleteLevelPrivilegeOperateDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;


import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

@Component
@Aspect
public class ItemLog {
    private static final Logger logger = LoggerFactory.getLogger(ItemLog.class);
    @Autowired
    OperateLogMapper operateLogMapper;
    @Autowired
    HttpServletRequest request; // 获取请求信息

    // 使用Jackson进行JSON序列化
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Around("@annotation(com.cskaoyan.wordmemorize.common.aspect.operate.OperateLog)")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取方法签名和注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        OperateLog operateLogAnnotation = method.getAnnotation(OperateLog.class);
        String dataType = operateLogAnnotation.dateType();
        int operateType = operateLogAnnotation.operateType();
        Object[] args = joinPoint.getArgs();

        // 2. 获取当前登录员工ID
        Long employeeId = StpKit.ADMIN.getLoginIdAsLong();

        // 3. 提前解析数据源（用于异常情况记录）
        Object dataSource = resolveDataSource(joinPoint, signature, args);

        // 4. 初始化日志实体
        OperateLogDO operateLogDO = new OperateLogDO();
        operateLogDO.setEmployeeId(employeeId);
        operateLogDO.setDataType(dataType);
        operateLogDO.setOperateType(operateType);

        Object result = null;
        try {
            // 5. 执行目标方法
            result = joinPoint.proceed(args);

            // 6. 方法执行成功
            operateLogDO.setStatus(1); // 成功

            // 7. 根据操作类型选择数据源
            if (operateType == OperateLogConstant.OPERATE_SINGLE_DELETE ||
                    operateType == OperateLogConstant.OPERATE_BATCH_DELETE||
                    operateType == OperateLogConstant.OPERATE_EXCEL_ADD
            ) {
                // 删除和EXCEL操作使用返回值
                operateLogDO.setData(objectMapper.writeValueAsString(result));
            } else {
                // 其他操作使用请求参数
                operateLogDO.setData(objectMapper.writeValueAsString(dataSource));
            }

            return result;
        } catch (Throwable e) {
            // 8. 方法执行失败
            operateLogDO.setStatus(0); // 失败
            operateLogDO.setData(objectMapper.writeValueAsString(dataSource));
            throw e; // 重新抛出异常，确保事务回滚
        } finally {
            // 10. 无论成功失败都记录日志
            operateLogMapper.insert(operateLogDO);
        }
    }
    /**
     * 智能解析操作数据源
     */
    private Object resolveDataSource(ProceedingJoinPoint joinPoint, MethodSignature signature, Object[] args) {
        // 情况1：无参数时返回空
        if (args.length == 0) return null;

        // 情况2：单个对象参数直接使用
        if (args.length == 1 && !isBasicType(args[0].getClass())) {
            return args[0];
        }

        // 情况3：多个参数或基础类型时构建参数映射
        Map<String, Object> paramMap = new LinkedHashMap<>();
        String[] paramNames = signature.getParameterNames();
        Class<?>[] paramTypes = signature.getParameterTypes();

        for (int i = 0; i < args.length; i++) {
            String name = (paramNames != null && i < paramNames.length)
                    ? paramNames[i] : "param" + i;

            // 跳过HttpServletRequest等特殊类型
            if (isExcludedType(paramTypes[i])) continue;

            paramMap.put(name, args[i]);
        }
        return paramMap;
    }

    /**
     * 判断是否基础类型
     */
    private boolean isBasicType(Class<?> clazz) {
        return clazz.isPrimitive() ||
                clazz == String.class ||
                Number.class.isAssignableFrom(clazz) ||
                clazz == Boolean.class;
    }

    /**
     * 排除不需要记录的参数类型
     */
    private boolean isExcludedType(Class<?> clazz) {
        return HttpServletRequest.class.isAssignableFrom(clazz) ||
                HttpServletResponse.class.isAssignableFrom(clazz) ||
                MultipartFile.class.isAssignableFrom(clazz);
    }

}
